﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using Amazon;
using Amazon.SimpleDB;
using Amazon.SimpleDB.Model;
using System.Threading;

namespace OnTime
{
    class AWSDatabase : IDisposable
    {
        private AmazonSimpleDB _sdb = AWSClientFactory.CreateAmazonSimpleDBClient("awsAccessKey", "awsSecretAccessKey");
        private string _fullName = string.Empty;

        public AWSDatabase()
        {}

        public string UserId 
        {
            get
            {
                return _fullName;
            }
            set
            {
                if (!value.IsNullOrWhitespace())
                {
                    _fullName = value.Trim();
                    _fullName = _fullName.ToLowerInvariant();
                    _fullName = _fullName.Replace(" ", string.Empty);
                }
                else
                    _fullName = string.Empty;
            }
        }

        private bool IsValid
        {
            get
            {
                return !_fullName.IsNullOrWhitespace();
            }
        }

        private string ProjectsItemName
        {
            get
            {
                string itemName = Guid.NewGuid().ToString();
                try
                {
                    var selectResponse = _sdb.Select(new SelectRequest() { SelectExpression = string.Format("SELECT itemName() from Projects WHERE UserId = '{0}'", _fullName) });
                    if (selectResponse.SelectResult.Item.Count == 1)
                        itemName = selectResponse.SelectResult.Item[0].Name;
                }
                catch (Exception)
                { }
                return itemName;
            }
        }

        public void InitFirstConnection()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(obj => 
            {
                try
                {
                    var selectResponse = _sdb.ListDomains(new ListDomainsRequest() { MaxNumberOfDomains = 1 });
                }
                catch (Exception)
                { }
            }));
        }

        public List<string> GetProjects()
        {
            var projects = new List<string>();
            if (!IsValid)
                return projects;

            try
            {
                var selectResponse = _sdb.Select(new SelectRequest() { SelectExpression = string.Format("SELECT Project from Projects WHERE UserId = '{0}'", _fullName) });
                foreach (var item in selectResponse.SelectResult.Item)
                {
                    foreach (var attr in item.Attribute)
                    {
                        Console.WriteLine(string.Format("Item: {0} - Name: {1} - Value: {2}", item.Name, attr.Name, attr.Value));
                        projects.Add(attr.Value);
                    }
                }
            }
            catch (Exception)
            { }
            return projects;
        }

        public List<Item> GetReports(int unixStartTime, int unixEndTime, string project)
        {
            List<Item> items = new List<Item>();
            if (!IsValid)
                return items;
            
            try
            {
                if (project.IsNullOrWhitespace())
                    project = string.Empty;
                else
                    project = string.Format("AND Project = '{0}' ", project);

                bool tokenSet;
                string token = null;
                do
                {
                    var selectResponse = _sdb.Select(new SelectRequest()
                    {
                        ConsistentRead = true,
                        NextToken = token,
                        SelectExpression = string.Format("SELECT * from TimeLogs WHERE " +
                            "UserId = '{0}' {1}AND StartTime > '{2}' AND EndTime < '{3}'", _fullName, project, unixStartTime, unixEndTime)
                    });
                    items.AddRange(selectResponse.SelectResult.Item);
                    tokenSet = selectResponse.SelectResult.IsSetNextToken();
                    token = selectResponse.SelectResult.NextToken;
                }
                while (tokenSet);
            }
            catch (Exception)
            { }
            return items;
        }

        public bool RemoveProject(string project)
        {
            bool success = false;
            if (!IsValid)
                return success;

            string itemName = ProjectsItemName;
            try
            {
                var deleteAttrResp = _sdb.DeleteAttributes(new DeleteAttributesRequest()
                {
                    DomainName = "Projects",
                    ItemName = itemName,
                    Attribute = new List<Amazon.SimpleDB.Model.Attribute>() 
                    { 
                        new Amazon.SimpleDB.Model.Attribute() 
                        { 
                            Name = "Project",
                            Value = project
                        }
                    }
                });
                success = true;
            }
            catch (Exception)
            { }
            return success;
        }

        public bool AddTimeLog(TimeLog timeLog)
        {
            bool success = false;
            if (!IsValid)
                return success;

            string logs = string.Empty;
            timeLog.Notes.ForEach(new Action<string>(note => logs += string.Format("{0} ", note ?? string.Empty)));

            try
            {
                var attribs = new List<ReplaceableAttribute>() 
                { 
                    new ReplaceableAttribute() 
                    {
                         Name = "UserId",
                         Value = timeLog.UserId
                    },
                    new ReplaceableAttribute()
                    {
                        Name = "Project",
                        Value = timeLog.Project
                    },
                    new ReplaceableAttribute()
                    {
                        Name = "StartTime",
                        Value = timeLog.StartTime.ToUnixTime().ToString()
                    },
                    new ReplaceableAttribute()
                    {
                        Name = "EndTime",
                        Value = timeLog.EndTime.ToUnixTime().ToString()
                    }
                };

                foreach (var log in timeLog.Notes)
                {
                    attribs.Add(new ReplaceableAttribute()
                    {
                        Name = "Note",
                        Value = log
                    });
                }

                var putAttrResp = _sdb.PutAttributes(new PutAttributesRequest()
                {
                    DomainName = "TimeLogs",
                    ItemName = timeLog.ID.ToString(),
                    Attribute = attribs
                });
                success = true;
            }
            catch (Exception)
            { }
            return success;
        }

        public bool RemoveTimeLogs(string project)
        {
            bool success = false;
            if (!IsValid || project.IsNullOrWhitespace())
                return success;

            try
            {
                var selectResponse = _sdb.Select(new SelectRequest() { SelectExpression = string.Format("SELECT * from TimeLogs WHERE UserId = '{0}' AND Project = '{1}'", _fullName, project) });
                foreach (var item in selectResponse.SelectResult.Item)
                {
                    _sdb.BatchDeleteAttributes(new BatchDeleteAttributesRequest()
                    {
                        DomainName = "TimeLogs",
                        Item = new List<DeleteableItem>() 
                    { 
                        new DeleteableItem() 
                        {
                            ItemName = item.Name,
                            Attribute = item.Attribute
                        }
                    }
                    });
                }
                success = true;
            }
            catch (Exception)
            { }
            return success;
        }

        public bool AddProject(string project)
        {
            bool success = false;
            if (!IsValid)
                return success;

            string itemName = ProjectsItemName;
            try
            {
                var putAttrResp = _sdb.PutAttributes(new PutAttributesRequest()
                {
                    DomainName = "Projects",
                    ItemName = itemName,
                    Attribute = new List<ReplaceableAttribute>() 
                    { 
                        new ReplaceableAttribute() 
                        { 
                            Name = "Project",
                            Value = project
                        },
                        new ReplaceableAttribute()
                        {
                            Name = "UserId",
                            Value = _fullName,
                            Replace = true
                        }
                    }
                });
                success = true;
            }
            catch (Exception)
            { }
            return success;
        }

        #region IDisposable Members
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
                _sdb.Dispose();
        }
        #endregion
    }
}
